// 表达式输入框
;(function($) {
	var V = {
		ttlOk:'&#xe656;',
		ttlError:'&#xe658;'
	}

	var myExpressInput = function(wrapper,options){
		options = options || {};
		this.options = $.extend({
			data: [],
			default:'',//默认值，表达式修改前，把当前值赋给控件
			logicKey:['or','and'], // 逻辑关键字
			equKey:['endWith','in','>','>=','<','<='], // 等式关键字
			groupKey:['(',')'], // 分组关键字
			onChange:function(){}
		}, options);
		this.wrapper = wrapper;
		this.placeholder = this.options.placeholder||"请输入逻辑表达式，支持【or、and、()、=、!=、in、not-in、begin-with、end-with】操作符；键盘上下键选择下拉列表。";
		this.maxHeight =300;//css里写死的最大高度300px
		this.init();		
	}

	myExpressInput.prototype = {
		init:function(){
			this.wrapper.empty();
			this.wrapper.html(this.getHtml());
			this.bindEvents();
			this.checkInput();
		},
		getHtml:function(){
			this.wrapper.attr('value', this.options.default);
			var html = '<div class="ttl-select-title">'+
						'<i class="ttlofont"></i>'+
						'<input type="text" placeholder="'+this.placeholder+'" value="'+this.options.default+'" class="ttl-input" autocomplete="off">'+
					'</div>';
			html+='<dl class="ttl-anim ttl-anim-upbit">';
			this.options.data.map(function(item){
				if(item.id==this.options.default){
					html+='<dd value="'+item.id+'" class="selected">'+item.title+'</dd>';
				}else{
					html+='<dd value="'+item.id+'">'+item.title+'</dd>';
				}
			}.bind(this))
			html+='</dl>';
			return html;
		},
		show:function(){
			this.wrapper.find('.ttl-select-title').addClass('ttl-showOpts');
			this.wrapper.find('dl').show();
		},
		hide:function(){
			this.wrapper.find('dl').hide();
			this.wrapper.find('.ttl-select-title').removeClass('ttl-showOpts');
		},
		selectItem:function($tar){
			var selText = $tar.text(),
			inputObj = this.wrapper.find('input'),
			myInputStr = inputObj.val();

			// 获取当前光标的位置，把选择值插入或替换该位置字符
			var focusPosition = 0|inputObj.attr('data-focus');

			var totalIndex = 0,isFinish = false,myInputArr = myInputStr.split(' ');
			myInputArr.map(function(item,index){
				if(isFinish) return;
				if(totalIndex > 0) totalIndex += 1;
				if (totalIndex+item.length < focusPosition) {
					// 焦点不在此项
					totalIndex += item.length;
				}else{
					// 焦点在此项，替换当前字符串
					myInputArr[index]=$.trim(selText);
					isFinish=true;
				}
			});
			inputObj.val(myInputArr.join(' '));
			this.hide();
			$tar.addClass('selected').siblings().removeClass('selected');
			inputObj.attr('data-focus',totalIndex+selText.length);
			this._setFocusPosition();
			this.checkInput();
		},
		_fixScroll: function() {
			var $dl=this.wrapper.find('dl');
			if ($dl.is(':hidden')) return;
			var item = $dl.find('dd.selected');
			if (!item.length) return;
			var offsetTop,
				upperBound,
				lowerBound,
				heightDelta = item.outerHeight();
			offsetTop = item[0].offsetTop;
			upperBound = $dl.scrollTop();
			lowerBound = upperBound + this.maxHeight - heightDelta;
			if (offsetTop < upperBound) {
				$dl.scrollTop(offsetTop);
			} else if (offsetTop > lowerBound) {
				$dl.scrollTop(offsetTop - this.maxHeight + heightDelta);
			}
		},
		// 向上向下选中
		_move: function(dir){
			var items = this.wrapper.find('dl dd'),
				current = items.filter('.selected'),
				index = current.prevAll('dd').length,
				total = items.length;
			switch(dir){
				case 'up':
					index--;
					(index < 0) && (index = (total - 1));
					break;
				case 'down':							
					current.length && index++;
					(index >= total) && (index = 0);							
					break;
			}
			items.eq(index).addClass('selected').siblings().removeClass('selected');
			this._fixScroll();
		},
		// 将input焦点定位在点击时位置
		_setFocusPosition: function() {
			var inputObj = this.wrapper.find('input'),
				posNum = 0|inputObj.attr('data-focus');
			if(inputObj[0].createTextRange){
				// IE
				var r = inputObj[0].createTextRange();
				r.moveStart('character', posNum);
				r.collapse(true);
				r.select();
			}else{
				// 非IE
				inputObj[0].setSelectionRange(posNum, posNum);
				inputObj.focus();
			}
		},
		// 获取当前光标在input中的位置
		_getFocusPosition:function(oTxt){
			var nullvalue = -1;
            var selectStart ;//选中开始位置
			var selectEnd ;//选中结束位置
			var position;//焦点位置
			var selectText;//选中内容
            if(oTxt.setSelectionRange){//非IE浏览器
                selectStart= oTxt.selectionStart;
				selectEnd = oTxt.selectionEnd;
				if(selectStart == selectEnd){
					position = oTxt.selectionStart;
					selectStart = nullvalue;
					selectEnd = nullvalue;
				}else{
					position = 	nullvalue;
				}
				selectText = oTxt.value.substring(selectStart,selectEnd);
            }else{//IE
                var range = document.selection.createRange();
				selectText=range.text;
                range.moveStart("character",-oTxt.value.length);
				position = range.text.length;
				selectStart = position - (selectText.length);
				selectEnd = selectStart + (selectText.length);
				if(selectStart != selectEnd){
					position = nullvalue;
				}else{
					selectStart = nullvalue;
					selectEnd = nullvalue;
				}
            }
            return position;
        },
        // 校验括号是否正确
		validBraces: function(str) {
	        // 匹配括号
	        var brackets = str.match(/[\[\]\(\)\{\}]/g),
	            arr = [],
	            symbol;
	        for (var i in brackets) {
	            switch (brackets[i]) {
	                case '(':
	                    arr.push('(');
	                    break;
	                case '[':
	                    arr.push('[');
	                    break;
	                case '{':
	                    arr.push('{');
	                    break;
	                case ')':
	                    symbol = arr.pop();
	                    if (symbol !== '(') return false;
	                    break;
	                case ']':
	                    symbol = arr.pop();
	                    if (symbol !== '[') return false;
	                    break;
	                case '}':
	                    symbol = arr.pop();
	                    if (symbol !== '{') return false;
	                    break

	            }
	        }
	        // 当存在 (() 这样的情况时, 上面的都能通过, 最后需要检测一下arr的长度
	        return arr.length > 0 ? false : true;
	    },
        // 校验内容是否正确
		checkInput:function(){
			var errmsg = '';
			var inputstr = this.wrapper.find('input').val(),
				iconObj = this.wrapper.find('.ttlofont');
			if(inputstr){
				// 判断分组关键字是否成对出现：()
				if(!this.validBraces(inputstr)){
					errmsg='括号不匹配';
				}else{
					// 有内容
					// 	name = alec and phone in 131|132|164 or gender = female
					var columnTitleArr = _.pluck(this.options.data, 'title'),
						_logicKey = this.options.logicKey,
						_equKey = this.options.equKey,
						_groupKey = this.options.groupKey;
					var inputArr = inputstr.split(' '),
						matchArr = [],
						errFormat = [
							'无效输入【$1】，位置：第$2个单词',
							'表达式必须以【英文左括号】或【数据列】开头，位置：第$1个单词',
							'表达式包含连续多个空格，位置：第$1个单词'
						];
					inputArr.map(function(item,index){
						if(errmsg){
							return;
						}
						if(index==0){
							// 第一个字符一定是：
							//  1.左括号(
							//  2.数据列
							if (!(item == '(' || _.contains(columnTitleArr, item))) {
								errmsg = Turtle.stringFormat(errFormat[1],index+1);
							}
						}else{
							if(item==''){
								if (index < inputArr.length - 1) {
									errmsg = Turtle.stringFormat(errFormat[2], index + 1);
								}
								return;
							}
							var preItem = this._getKeyByIndex(index-1); // group1/group2/logic/equ/column/value
							switch (preItem) {
								case 'logic':
									// column/group1
									errmsg = _.contains(columnTitleArr,item) || _.contains(_groupKey,item) ? '' : Turtle.stringFormat(errFormat[0],item,index+1);
									break;
								case 'group1':
									// column
									errmsg = _.contains(columnTitleArr,item) ? '' : Turtle.stringFormat(errFormat[0],item,index+1);
									break;
								case 'equ':
									// value
									errmsg = !_.contains(_logicKey, item) && !_.contains(_equKey, item) && !_.contains(_groupKey, item) ? '' : Turtle.stringFormat(errFormat[0],item,index+1);
									break;
								case 'column':
									// equ
									errmsg = _.contains(_equKey,item) ? '' : Turtle.stringFormat(errFormat[0],item,index+1);
									break;
								case 'value':
									// logic/gropu2
									errmsg = _.contains(_logicKey,item) || _.contains(_groupKey,item) ? '' : Turtle.stringFormat(errFormat[0],item,index+1);
									break;
								case 'group2':
									// logic
									errmsg = _.contains(_logicKey,item) ? '' : Turtle.stringFormat(errFormat[0],item,index+1);
									break;
							}
						}

					}.bind(this));
				}

				if(errmsg){
					console.log(errmsg);
					this.wrapper.removeClass('ttl-ok').addClass('ttl-error');
					iconObj.html(V.ttlError);
					this.wrapper.find('.ttlofont').attr('data-errmsg',errmsg);
				}else{
					this.wrapper.removeClass('ttl-error').addClass('ttl-ok');
					iconObj.html(V.ttlOk);
				}
			}else{
				// 无内容，正确
				this.wrapper.removeClass('ttl-error').addClass('ttl-ok');
				iconObj.html(V.ttlOk);
			}
		},
		// 判断当前索引项的关键字类型：
		// 	group1/group2/logic/equ/column/value
		_getKeyByIndex: function(index) {
			var thisValue = this.wrapper.find('input').val(),
				myValueArr = thisValue.split(' ');
			if (myValueArr.length < index + 1){
				return '';
			}
			var item = myValueArr[index];

			var columnTitleArr = _.pluck(this.options.data, 'title'),
				_logicKey = this.options.logicKey,
				_equKey = this.options.equKey,
				_groupKey = this.options.groupKey;

			// 焦点在此项					
			if (_.contains(_groupKey, myValueArr[index])) {
				// 判断分组关键字
				// 	1.当前项为分组关键字'('或')'
				return myValueArr[index] == '(' ? 'group1' : 'group2';

			} else if (
				// _.contains(_logicKey,item) || 
				myValueArr[index - 2] && _.contains(_equKey, myValueArr[index - 2]) ||
				myValueArr[index - 1] && myValueArr[index - 1] == ')'
			) {
				// 判断逻辑关键字
				////  1. 当前项为逻辑关键字
				//  2. 前前一个为等式关键字
				//  3. 前一个是右括号)
				return 'logic';
			} else if (
				// _equKey.indexOf(item)>-1 || 
				_.contains(columnTitleArr, myValueArr[index - 1]) && !myValueArr[index - 2] ||
				_.contains(columnTitleArr, myValueArr[index - 1]) && _.contains(_logicKey, myValueArr[index - 2]) ||
				_.contains(columnTitleArr, myValueArr[index - 1]) && myValueArr[index - 2] == '('
			) {
				// 判断等式
				//// 1. 当前项为等式关键字
				//  2. 前一个为数据列，且为起始字符
				//  3. 前一个为数据列，且前前一个为逻辑关键字
				//  4. 前一个为数据列，且前前一个为左括号(
				return 'equ';
			} else {
				if (myValueArr[0]==item ||
					// myValueArr.length >= index + 1 && _.contains(_equKey, myValueArr[index + 1]) ||
					_.contains(_logicKey, myValueArr[index - 1]) ||
					myValueArr[index - 1] && myValueArr[index - 1] == '('
				) {
					// 判断数据列
					//  1. 当前项为第一项内容
					////  2. 下一个是等式关键字
					//  3. 前一项是逻辑关键字
					//  4. 前一个项是左括号(
					return 'column';
				} else if (index > 0 && _.contains(_equKey, myValueArr[index - 1])) {
					// 判断数据值
					//  1. 前一个是等式关键字
					return 'value';
				}
			};
			return '';
		},
		// name = alec and gender != femal or age = 28
		// 根据当前焦点，判断用户将要输入的是：数据列、自定义值、逻辑关键字
		// data:[{id:123,title:'name'}],
		// logicKey:['or','and'], // 逻辑关键字
		// equKey:['=','!='], // 等式关键字
		_checkWillInput:function(){
			var currentObj = this.wrapper.find('input');
			var position = this._getFocusPosition(currentObj[0]);

			var thisValue = currentObj.val(),
				myValueArr = thisValue.split(' ');

			var totalIndex = 0,expType = '';
			myValueArr.map(function(item,index){
				if(expType) return;
				if(totalIndex > 0) totalIndex += 1;
				if (totalIndex+item.length < position) {
					// 焦点不在此项
					totalIndex += item.length;
				}else{
					expType = this._getKeyByIndex(index);
					// 到最后了，仍然没有找到匹配项
					// if (totalIndex == thisValue.length) {
					// 	// 递归获取前一个对象的类型，从而判断当前对象类型
					// 	switch (this._checkWillInput(position - 1,isClick)) {
					// 		case 'logic':
					// 			expType = 'column'
					// 			break;
					// 		case 'equ':
					// 			expType = 'value'
					// 			break;
					// 		case 'column':
					// 			expType = 'equ'
					// 			break;
					// 		case 'value':
					// 		case 'group':
					// 			expType = 'logic'
					// 			break;
					// 	}
					// }
				}
			}.bind(this));
			return expType;
		},
		// 根据表达式关键字类型，显示下拉选择框
		showSelectListByExpType: function(expType,isFilter) {
			var inputObj = this.wrapper.find('input');
			if (inputObj.length) {
				var dataSource = [];
				switch (expType) {
					case 'logic':
						dataSource = this.options.logicKey;
						break;
					case 'equ':
						dataSource = this.options.equKey;
						break;
					case 'column':
						dataSource = this.options.data;
						break;
					case 'group1':
					case 'group2':
						dataSource = this.options.groupKey;
						break;
					case 'value':
						dataSource = [];
						break;
				}
				if(dataSource.length==0){
					this.hide();
					return;
				}
				var selectData = {
					value: ''
				};
				var html = '';
				dataSource.map(function(item) {
					var thisItem = item;
					if (typeof thisItem == 'string') {
						// 只有列是完整的[id-title]结构，其他类型只有title
						// 这里需要手动设置其id
						thisItem = {
							id: thisItem,
							title: thisItem
						}
					}
					if (isFilter) {
						// 根据实时输入，过滤数据项						
						// 获取当前光标的位置，把选择值插入或替换该位置字符
						var focusPosition = 0|inputObj.attr('data-focus');
						var totalIndex = 0,isFinish = false,inputKey = '' ,myInputArr = inputObj.val().split(' ');
						myInputArr.map(function(item,index){
							if(isFinish) return;
							if(totalIndex > 0) totalIndex += 1;
							if (totalIndex+item.length < focusPosition) {
								// 焦点不在此项
								totalIndex += item.length;
							}else{
								// 焦点在此项，替换当前字符串
								isFinish=true;
								inputKey = item;
							}
						});
						if (inputKey && thisItem.title.indexOf(inputKey) == -1) {
							return;
						}
					}
					html += '<dd value="' + thisItem.id + '">' + thisItem.title + '</dd>';
				});
				this.wrapper.find('dl').html(html);
			}
			this.show();
		},
		bindEvents:function(){
			this.wrapper.bind('click',function(e){
				var $tar = $(e.target || e.srcElement);
				if($tar.is('i.ttlofont')){
					return;
				}
				var focusPosition = this._getFocusPosition(this.wrapper.find('input')[0]);

				this.wrapper.find('input').attr('data-focus',focusPosition);//把焦点位置记录到input元素属性上
				if($tar.is('input') && $tar.closest('.ttl-select-title').length){
					// 点击输入框，显示下拉项
					var willInput = this._checkWillInput();
					console.log(willInput);
					this.showSelectListByExpType(willInput,false);
				}else if($tar.is('dd')){
					// 点击下拉选项，选中下拉项
					this.selectItem($tar);
				}
			}.bind(this));

			// 值改变时触发（仅限手动输入改变）
			this.wrapper.find('input').bind('input propertychange',function(e){
				e = e || window.event,
				$tar = $(e.target || e.srcElement);
				// 重置当前焦点
				var focusPosition = this._getFocusPosition($tar[0]);
				this.wrapper.find('input').attr('data-focus',focusPosition);//把焦点位置记录到input元素属性上

				var willInput = this._checkWillInput();
				console.log(willInput);
				this.showSelectListByExpType(willInput,true);
				this.checkInput();
			}.bind(this));

			
			// 绑定键盘按下事件 (仅限可输入过滤下拉框) 
			this.wrapper.find('input').length && 
			this.wrapper.bind('keyup',function(e) {
				e = e || window.event,
        		key = e.keyCode || e.which || e.charCode,
        		inputObj = this.wrapper.find('input');

				switch (key) {
					case 13:
						// 回车
						this.selectItem(this.wrapper.find('dl dd.selected'));
						break;
					case 32:
						// 空格
						// inputObj.attr('data-focus',this._getFocusPosition(inputObj[0]));
						// var willInput = this._checkWillInput();
						// console.log(willInput);
						break;
					case 38:
        				this._setFocusPosition();
						// up
						this._move('up');
						break;
					case 40:
        				this._setFocusPosition();
						// down
						this._move('down');
						break;

					default:
						break;
				}
			}.bind(this));

			// 点击其他部分，隐藏下拉项
			$(document).bind('mouseup', function(e) {
				var $tar = $(e.target || e.srcElement);
				if($tar[0]!=this.wrapper.find('dl')[0]){
					var box = this.wrapper.find('dl');
					if (box && !box.is(":hidden")) {
						this.hide();
					}
				}
			}.bind(this));

			// 鼠标悬停错误icon，进行错误提示
			var tipIndex = -1;
			this.wrapper.find('.ttlofont').hover(function() {
				if($(this).closest('.ttl-error').length==0){
					return;
				}
				var msg = $(this).attr('data-errmsg')||'';
				if(msg){
					tipIndex = Turtle.layer.tips(msg, $(this), {
						tips: 1,
						time: -1
					});
				}
			},function(){
				tipIndex > -1 && Turtle.layer.close(tipIndex);
			});
		}
	}

	$.fn.uiExpressInput = function(options) {
		new myExpressInput(this, options);
	};
})(jQuery)